﻿using System;
using System.Collections.Generic;
using System.Linq;
using Borg.AddOn;
using Borg.Properties;

namespace Borg
{
    [Serializable]
    public class InstanceStore : RuntimeElement, IInstanceStoreReader
    {
        public readonly Dictionary<Slot, MetaElementCollection<Tag>> slotTagCollections;
        private readonly Dictionary<Plug, MetaElementCollection<Tag>> _plugTagCollections;

        private readonly Dictionary<object, Extension> _extensionObjectDictionary;
        private readonly Dictionary<int, Extension> _extensionIdDictionary;
        private readonly Dictionary<string, MetaElementCollection<Extension>> _extensionDictionary;

        private readonly Dictionary<int, Plug> _plugIdDictionary;
        private readonly Dictionary<string, MetaElementCollection<Plug>> _plugDictionary;

        private readonly Dictionary<int, Slot> _slotIdDictionary;
        private readonly Dictionary<string, MetaElementCollection<Slot>> _slotDictionary;

        private IInstanceStoreSubstitutionHook _substitutionHook;

        public IEnumerable<Extension> Extensions
        {
            get
            {
                if (!CheckAccess())
                    throw GetAccessException();

                return TypeStore.ExtensionTypes.
                    SelectMany(extensionType => extensionType.extensions);
            }
        }

        public IEnumerable<Plug> Plugs
        {
            get
            {
                if (!CheckAccess())
                    throw GetAccessException();

                return Extensions.SelectMany(extension => extension.Plugs);
            }
        }

        public IEnumerable<Slot> Slots
        {
            get
            {
                if (!CheckAccess())
                    throw GetAccessException();

                return Extensions.SelectMany(extension => extension.Slots);
            }
        }

        public IEnumerable<Tag> Tags
        {
            get
            {
                if (!CheckAccess())
                    throw GetAccessException();

                return slotTagCollections.Values.
                    SelectMany(elementCollection => elementCollection);
            }
        }

        protected internal InstanceStore(Runtime runtime)
            : base(runtime)
        {
            slotTagCollections = new Dictionary<Slot, MetaElementCollection<Tag>>();
            _plugTagCollections = new Dictionary<Plug, MetaElementCollection<Tag>>();

            _extensionObjectDictionary = new Dictionary<object, Extension>();
            _extensionIdDictionary = new Dictionary<int, Extension>();

            _extensionDictionary = new Dictionary<string, MetaElementCollection<Extension>>();

            _plugIdDictionary = new Dictionary<int, Plug>();
            _plugDictionary = new Dictionary<string, MetaElementCollection<Plug>>();

            _slotIdDictionary = new Dictionary<int, Slot>();
            _slotDictionary = new Dictionary<string, MetaElementCollection<Slot>>();
        }

        internal void Init(IInstanceStoreSubstitutionHook substitutionHook)
        {
            _substitutionHook = substitutionHook;
        }

        public Extension GetExtension(int id)
        {
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetExtension(id);
        }

        public Plug GetPlug(int id)
        {
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetPlug(id);
        }

        public Slot GetSlot(int id)
        {
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetSlot(id);
        }

        public MetaElementCollection<Extension> GetExtensions(string name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            
            if (name == string.Empty)
                throw new ArgumentException(Exceptions.Name_must_not_be_empty);
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetExtensions(name);
        }

        public MetaElementCollection<Plug> GetPlugs(string name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            
            if (name == string.Empty)
                throw new ArgumentException(Exceptions.Name_must_not_be_empty);
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetPlugs(name);
        }

        public MetaElementCollection<Slot> GetSlots(string name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            
            if (name == string.Empty)
                throw new ArgumentException(Exceptions.Name_must_not_be_empty);
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetSlots(name);
        }

        public MetaElementCollection<Slot> GetSlotsWherePlugged(Plug plug)
        {
            if (plug == null)
                throw new ArgumentNullException("plug");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetSlotsWherePlugged(plug);
        }

        public MetaElementCollection<Plug> GetPluggedPlugs(Slot slot)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetPluggedPlugs(slot);
        }

        public MetaElementCollection<Tag> GetTags(Plug plug)
        {
            if (plug == null)
                throw new ArgumentNullException("plug");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetTags(plug);
        }

        public MetaElementCollection<Tag> GetTags(Slot slot)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetTags(slot);
        }

        public MetaElementCollection<Extension> GetExtensions(ExtensionType extensionType)
        {
            if (extensionType == null)
                throw new ArgumentNullException("extensionType");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetExtensions(extensionType);
        }

        public Extension GetSharedExtension(ExtensionType extensionType)
        {
            if (extensionType == null)
                throw new ArgumentNullException("extensionType");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetSharedExtension(extensionType);
        }

        public Extension GetExtension(object extensionObject)
        {
            if (extensionObject == null)
                throw new ArgumentNullException("extensionObject");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetExtension(extensionObject);
        }

        public object GetExtensionObject(Extension extension)
        {
            if (extension == null)
                throw new ArgumentNullException("extension");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetExtensionObject(extension);
        }

        public Plug GetPlug(object extensionObject, string name)
        {
            if (extensionObject == null)
                throw new ArgumentNullException("extensionObject");
            
            if (name == null)
                throw new ArgumentNullException("name");
            
            if (name == string.Empty)
                throw new ArgumentException(Exceptions.Name_must_not_be_empty, "name");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetPlug(extensionObject, name);
        }

        public Slot GetSlot(object extensionObject, string name)
        {
            if (extensionObject == null)
                throw new ArgumentNullException("extensionObject");
            
            if (name == null)
                throw new ArgumentNullException("name");
            
            if (name == string.Empty)
                throw new ArgumentException(Exceptions.Name_must_not_be_empty, "name");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetSlot(extensionObject, name);
        }

        public bool IsDestroyed(Extension extension)
        {
            if (extension == null)
                throw new ArgumentNullException("extension");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalIsDestroyed(extension);
        }

        public bool GetShared(Extension extension)
        {
            if (extension == null)
                throw new ArgumentNullException("extension");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetShared(extension);
        }

        public bool IsActivated(Extension extension)
        {
            if (extension == null)
                throw new ArgumentNullException("extension");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalIsActivated(extension);
        }

        public bool IsOpen(Slot slot)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalIsOpen(slot);
        }

        public bool IsPlugged(Slot slot, Plug plug)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (plug == null)
                throw new ArgumentNullException("plug");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalIsPlugged(slot, plug);
        }

        public bool IsTagged(Slot slot, Plug plug, string tag)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (plug == null)
                throw new ArgumentNullException("plug");
            
            if (string.IsNullOrEmpty(tag))
                throw new ArgumentException(Messages.InstanceStore_TagMustNoBeNullOrEmpty, "tag");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalIsTagged(slot, plug, tag);
        }

        public bool GetAutoOpen(Slot slot)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetAutoOpen(slot);
        }

        public bool GetAutoPlug(Slot slot)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetAutoPlug(slot);
        }

        public string[] GetAutoTag(Slot slot)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetAutoTag(slot);
        }

        public bool GetShared(Slot slot)
        {
            if (slot == null)
                throw new ArgumentNullException("slot");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetShared(slot);
        }

        public bool GetAutoPlug(Plug plug)
        {
            if (plug == null)
                throw new ArgumentNullException("plug");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetAutoPlug(plug);
        }

        public string[] GetAutoTag(Plug plug)
        {
            if (plug == null)
                throw new ArgumentNullException("plug");
            
            if (!CheckAccess())
                throw GetAccessException();
            
            return InternalGetAutoTag(plug);
        }

        internal Extension InternalGetExtension(int id)
        {
            return
                _extensionIdDictionary.ContainsKey(id)
                    ? _extensionIdDictionary[id]
                    : null;
        }

        internal Plug InternalGetPlug(int id)
        {
            return
                _plugIdDictionary.ContainsKey(id)
                    ? _plugIdDictionary[id]
                    : null;
        }

        internal Slot InternalGetSlot(int id)
        {
            return
                _slotIdDictionary.ContainsKey(id)
                ? _slotIdDictionary[id]
                : null;
        }

        internal MetaElementCollection<Extension> InternalGetExtensions(string name)
        {
            return
                _extensionDictionary.ContainsKey(name)
                    ? _extensionDictionary[name]
                    : (_extensionDictionary[name] =
                       new MetaElementCollection<Extension>());
        }

        internal MetaElementCollection<Plug> InternalGetPlugs(string name)
        {
            return
                _plugDictionary.ContainsKey(name)
                    ? _plugDictionary[name]
                    : (_plugDictionary[name] =
                       new MetaElementCollection<Plug>());
        }

        internal MetaElementCollection<Slot> InternalGetSlots(string name)
        {
            return
                _slotDictionary.ContainsKey(name)
                    ? _slotDictionary[name]
                    : (_slotDictionary[name] =
                       new MetaElementCollection<Slot>());
        }

        internal MetaElementCollection<Slot> InternalGetSlotsWherePlugged(Plug plug)
        {
            return plug.slotsWherePlugged;
        }

        internal MetaElementCollection<Plug> InternalGetPluggedPlugs(Slot slot)
        {
            return slot.pluggedPlugs;
        }

        internal MetaElementCollection<Tag> InternalGetTags(Plug plug)
        {
            return
                _plugTagCollections.ContainsKey(plug)
                    ? _plugTagCollections[plug]
                    : (_plugTagCollections[plug] =
                       new MetaElementCollection<Tag>());
        }

        internal MetaElementCollection<Tag> InternalGetTags(Slot slot)
        {
            return
                slotTagCollections.ContainsKey(slot)
                    ? slotTagCollections[slot]
                    : (slotTagCollections[slot] =
                       new MetaElementCollection<Tag>());
        }

        internal Tag InternalGetTag(Slot slot, Plug plug, string name)
        {
            return
                slotTagCollections.ContainsKey(slot)
                    ? slotTagCollections[slot].FirstOrDefault(
                        tag => tag.Plug == plug && tag.Name == name)
                    : null;
        }

        internal MetaElementCollection<Extension> InternalGetExtensions(ExtensionType extensionType)
        {
            return extensionType.extensions;
        }

        internal Extension InternalGetSharedExtension(ExtensionType extensionType)
        {
            return extensionType.sharedExtension;
        }

        internal Extension InternalGetExtension(object extensionObject)
        {
            return
                _extensionObjectDictionary.ContainsKey(extensionObject)
                    ? _extensionObjectDictionary[extensionObject]
                    : null;
        }

        internal object InternalGetExtensionObject(Extension extension)
        {
            return extension.extensionObject;
        }

        internal Plug InternalGetPlug(object extensionObject, string name)
        {
            return
                _extensionObjectDictionary.ContainsKey(extensionObject)
                    ? _extensionObjectDictionary[extensionObject].Plugs[name]
                    : null;
        }

        internal Slot InternalGetSlot(object extensionObject, string name)
        {
            return
                _extensionObjectDictionary.ContainsKey(extensionObject)
                    ? _extensionObjectDictionary[extensionObject].Slots[name]
                    : null;
        }

        protected internal virtual bool InternalIsDestroyed(Extension extension)
        {
            return !extension.ExtensionType.extensions.Contains(extension);
        }

        protected internal virtual bool InternalGetShared(Extension extension)
        {
            return extension.ExtensionType.sharedExtension == extension;
        }

        protected internal virtual bool InternalIsActivated(Extension extension)
        {
            return extension.extensionObject != null;
        }

        protected internal virtual bool InternalIsOpen(Slot slot)
        {
            return slot.isOpen;
        }

        protected internal virtual bool InternalIsPlugged(Slot slot, Plug plug)
        {
            _substitutionHook.SubstituteForIsPlugged(ref slot, ref plug);
            return plug.slotsWherePlugged.Contains(slot);
        }

        protected internal virtual bool InternalIsTagged(Slot slot, Plug plug, string name)
        {
            _substitutionHook.SubstituteForIsTagged(ref slot, ref plug, name);
            return InternalGetTag(slot, plug, name) != null;
        }

        protected internal virtual bool InternalGetAutoOpen(Slot slot)
        {
            return slot.autoOpen;
        }

        protected internal virtual bool InternalGetAutoPlug(Slot slot)
        {
            return slot.autoPlug;
        }

        protected internal virtual string[] InternalGetAutoTag(Slot slot)
        {
            return slot.autoTag;
        }

        protected internal virtual bool InternalGetShared(Slot slot)
        {
            return slot.shared;
        }

        protected internal virtual bool InternalGetAutoPlug(Plug plug)
        {
            return plug.autoPlug;
        }

        protected internal virtual string[] InternalGetAutoTag(Plug plug)
        {
            return plug.autoTag;
        }

        [Serializable]
        public class Modifier : IInstanceStoreModifier
        {
            private readonly InstanceStore _store;

            public Modifier(InstanceStore store)
            {
                _store = store;
            }

            public void AddExtension(Extension extension)
            {
                if (extension == null)
                    throw new ArgumentNullException("extension");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (_store.InternalGetExtensions(extension.ExtensionType).Contains(extension))
                    throw new InvalidOperationException("Extension is already added");
                
                InternalAddExtension(extension);
            }

            public void RemoveExtension(Extension extension)
            {
                if (extension == null)
                    throw new ArgumentNullException("extension");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (!_store.InternalGetExtensions(extension.ExtensionType).Contains(extension))
                    throw new InvalidOperationException("Extension is not added");
                
                InternalRemoveExtension(extension);
            }

            public void SetSharedExtension(Extension extension)
            {
                if (extension == null)
                    throw new ArgumentNullException("extension");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();

                InternalSetSharedExtension(extension);
            }

            public void AddActivated(Extension extension, object extensionObject)
            {
                if (extension == null)
                    throw new ArgumentNullException("extension");
                
                if (extensionObject == null)
                    throw new ArgumentNullException("extensionObject");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (_store.InternalGetExtensionObject(extension) != null)
                    throw new InvalidOperationException("Extension object is already added");
                
                InternalAddActivated(extension, extensionObject);
            }

            public void RemoveActivated(Extension extension)
            {
                if (extension == null)
                    throw new ArgumentNullException("extension");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (_store.InternalGetExtensionObject(extension) == null)
                    throw new InvalidOperationException("Extension object is not added");
                
                InternalRemoveActivated(extension);
            }

            public void AddOpened(Slot slot)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (_store.InternalIsOpen(slot))
                    throw new InvalidOperationException("Slot is already open");
                
                InternalAddOpened(slot);
            }

            public void RemoveOpened(Slot slot)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (!_store.InternalIsOpen(slot))
                    throw new InvalidOperationException("Slot is not open");
                
                InternalRemoveOpened(slot);
            }

            public void AddPlugged(Slot slot, Plug plug)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (plug == null)
                    throw new ArgumentNullException("plug");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (_store.InternalIsPlugged(slot, plug))
                    throw new InvalidOperationException("Slot and Plug are already plugged");
                
                InternalAddPlugged(slot, plug);
            }

            public void RemovePlugged(Slot slot, Plug plug)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (plug == null)
                    throw new ArgumentNullException("plug");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                if (!_store.InternalIsPlugged(slot, plug))
                    throw new InvalidOperationException("Slot and Plug are not plugged");
                
                InternalRemovePlugged(slot, plug);
            }

            public void AddTag(Tag tag)
            {
                if (tag == null)
                    throw new ArgumentNullException("tag");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalAddTag(tag);
            }

            public void RemoveTag(Tag tag)
            {
                if (tag == null)
                    throw new ArgumentNullException("tag");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalRemoveTag(tag);
            }

            public void SetAutoOpen(Slot slot, bool value)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalSetAutoOpen(slot, value);
            }

            public void SetAutoPlug(Slot slot, bool value)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalSetAutoPlug(slot, value);
            }

            public void SetAutoTag(Slot slot, string[] value)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalSetAutoTag(slot, value);
            }

            public void SetShared(Slot slot, bool value)
            {
                if (slot == null)
                    throw new ArgumentNullException("slot");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalSetShared(slot, value);
            }

            public void SetAutoPlug(Plug plug, bool value)
            {
                if (plug == null)
                    throw new ArgumentNullException("plug");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalSetAutoPlug(plug, value);
            }

            public void SetAutoTag(Plug plug, string[] value)
            {
                if (plug == null)
                    throw new ArgumentNullException("plug");
                
                if (!_store.CheckAccess())
                    throw GetAccessException();
                
                InternalSetAutoTag(plug, value);
            }

            internal void InternalAddExtension(Extension extension)
            {
                extension.ExtensionType.extensions.Add(extension);
                _store._extensionIdDictionary.Add(extension.Id, extension);

                (_store._extensionDictionary.ContainsKey(extension.Name)
                     ? _store._extensionDictionary[extension.Name]
                     : (_store._extensionDictionary[extension.Name] =
                        new MetaElementCollection<Extension>())).Add(extension);
                
                foreach (var plug in extension.Plugs)
                {
                    _store._plugIdDictionary.Add(plug.Id, plug);

                    (_store._plugDictionary.ContainsKey(plug.Name)
                         ? _store._plugDictionary[plug.Name]
                         : (_store._plugDictionary[plug.Name] =
                            new MetaElementCollection<Plug>())).Add(plug);
                }
                
                foreach (var slot in extension.Slots)
                {
                    _store._slotIdDictionary.Add(slot.Id, slot);

                    (_store._slotDictionary.ContainsKey(slot.Name)
                         ? _store._slotDictionary[slot.Name]
                         : (_store._slotDictionary[slot.Name] =
                            new MetaElementCollection<Slot>())).Add(slot);
                }
            }

            internal void InternalRemoveExtension(Extension extension)
            {
                var extensionType = extension.ExtensionType;
                extensionType.extensions.Remove(extension);
                
                if (extensionType.sharedExtension == extension)
                    extensionType.sharedExtension = null;
                
                _store._extensionIdDictionary.Remove(extension.Id);
                _store._extensionDictionary[extension.Name].Remove(extension);
                
                foreach (var plug in extension.Plugs)
                {
                    _store._plugIdDictionary.Remove(plug.Id);
                    _store._plugDictionary[plug.Name].Remove(plug);
                    _store._plugTagCollections.Remove(plug);
                }

                foreach (var slot in extension.Slots)
                {
                    _store._slotIdDictionary.Remove(slot.Id);
                    _store._slotDictionary[slot.Name].Remove(slot);
                    _store.slotTagCollections.Remove(slot);
                }
            }

            internal void InternalSetSharedExtension(Extension extension)
            {
                extension.ExtensionType.sharedExtension = extension;
            }

            internal void InternalAddActivated(Extension extension, object extensionObject)
            {
                extension.extensionObject = extensionObject;
                _store._extensionObjectDictionary.Add(extensionObject, extension);
            }

            internal void InternalRemoveActivated(Extension extension)
            {
                _store._extensionObjectDictionary.Remove(extension.extensionObject);
                extension.extensionObject = null;
            }

            internal void InternalAddOpened(Slot slot)
            {
                slot.isOpen = true;
            }

            internal void InternalRemoveOpened(Slot slot)
            {
                slot.isOpen = false;
            }

            internal void InternalAddPlugged(Slot slot, Plug plug)
            {
                slot.pluggedPlugs.Add(plug);
                plug.slotsWherePlugged.Add(slot);
            }

            internal void InternalRemovePlugged(Slot slot, Plug plug)
            {
                slot.pluggedPlugs.Remove(plug);
                plug.slotsWherePlugged.Remove(slot);
            }

            internal void InternalAddTag(Tag tag)
            {
                _store.InternalGetTags(tag.Plug).Add(tag);
                _store.InternalGetTags(tag.Slot).Add(tag);
            }

            internal void InternalRemoveTag(Tag tag)
            {
                _store.InternalGetTags(tag.Plug).Remove(tag);
                _store.InternalGetTags(tag.Slot).Remove(tag);
            }

            internal void InternalSetAutoOpen(Slot slot, bool value)
            {
                slot.autoOpen = value;
            }

            internal void InternalSetAutoPlug(Slot slot, bool value)
            {
                slot.autoPlug = value;
            }

            internal void InternalSetAutoTag(Slot slot, string[] value)
            {
                slot.autoTag = value;
            }

            internal void InternalSetShared(Slot slot, bool value)
            {
                slot.shared = value;
            }

            internal void InternalSetAutoPlug(Plug plug, bool value)
            {
                plug.autoPlug = value;
            }

            internal void InternalSetAutoTag(Plug plug, string[] value)
            {
                plug.autoTag = value;
            }
        }
    }
}
